home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- *
- * draw.c
- *
- * Part of the "Curve Demo"
- * by Howard Look for Silicon Graphics
- *
- * June, 1989
- *
- * This file contains the routines used for drawing on the screen,
- * including drawing the curve, the control points, and the view
- * volume. This file also contains routines for maintaining the position
- * and motion of the control points.
- *
- */
-
-
- #include <stdio.h>
- #include <gl.h>
- #include <device.h>
- #include <math.h>
- #include "curve.h"
- #include "event.h"
- #include "spaced.h"
-
-
- /* Prototypes */
- void init_basis(void);
- void init_linestyles(void);
- void clear_window(void);
- void draw_display(void);
- void draw_markers(void);
- void draw_hulls(void);
- void draw_drop_lines(Coord c[3]);
- void update_positions(void);
- void add_control_point(void);
- void delete_control_point(void);
- void move_control_point(int);
- void track_motion();
- int get_close_marker(float, float);
- float generate_random_float(float);
- void draw_cube(void);
- void draw_volume(void);
- Boolean hit_control_point(int *);
- void fake_view_volume(void);
- void fake_control_volume(void);
-
- extern void help(int);
- extern Boolean helping(void);
-
- extern Boolean within_cube(void);
-
- /* basis matrix for Bezier splines */
- Matrix bezier_matrix =
- { {-1.0, 3.0, -3.0, 1.0},
- { 3.0, -6.0, 3.0, 0.0},
- {-3.0, 3.0, 0.0, 0.0},
- { 1.0, 0.0, 0.0, 0.0}
- };
-
-
- /* basis matrix for cardinal splines */
- Matrix cardinal_matrix =
- { {-0.5, 1.5, -1.5, 0.5},
- { 1.0, -2.5, 2.0, -0.5},
- {-0.5, 0.0, 0.5, 0.0},
- { 0.0, 1.0, 0.0, 0.0}
- };
-
-
- /* basis matrix for B-splines */
- Matrix bspline_matrix =
- { {-1.0/6.0, 3.0/6.0, -3.0/6.0, 1.0/6.0},
- { 3.0/6.0, -6.0/6.0, 3.0/6.0, 0.0},
- {-3.0/6.0, 0.0, 3.0/6.0, 0.0},
- { 1.0/6.0, 4.0/6.0, 1.0/6.0, 0.0}
- };
-
-
- /* Array of control points that define the geometry of the curve */
- Coord geometry[MAX_MARKERS][3];
-
-
- /* Array of dx,dy,dz for each control point, used to create motion */
- float offset[MAX_MARKERS][3];
-
-
- /* Number of control point markers currently being used */
- int current_markers = 0;
-
-
- /*
- * if motion is on while trying to move a point, nail that point to
- * the cursor.
- */
- Boolean moving = FALSE;
- int nailed_marker;
-
- Matrix everything_matrix;
-
- /* Environment variables */
- extern
- int curve_basis,
- display_mode,
- curve_precision,
- speed,
- line_style,
- whizbang;
- extern
- Boolean markers,
- hulls,
- motion,
- smear;
-
- extern
- int hardware;
-
-
- /* About the window... */
- extern int origin_x, origin_y, size_x, size_y;
-
-
- /* Rotation matrix for the view volume */
- extern Matrix rotate_matrix;
-
-
- /*
- * Defines the basis matrices so we can use them later.
- */
- void init_basis(void)
- {
- defbasis(BEZIER, bezier_matrix);
- defbasis(CARDINAL, cardinal_matrix);
- defbasis(BSPLINE, bspline_matrix);
- }
-
-
- /*
- * Initializes the linestyles so we can use them.
- */
- void init_linestyles(void)
- {
- /* Solid pattern is pre-defined */
- deflinestyle(DOTTED, DOTTED_PATTERN);
- deflinestyle(DASHED, DASHED_PATTERN);
- }
-
- /*
- * Completely draws the display. Called by the event manager whenever
- * there is no event queue activity.
- */
- void draw_display(void)
- {
- if (!current_markers)
- {
- help(TRUE);
- return;
- }
- if (helping())
- {
- draw_instructions(FALSE);
- return;
- }
-
- if (! smear)
- czclear(0,getgdesc(GD_ZMAX));
-
- if (display_mode == THREE_D)
- {
- set_three_d_view();
- /* apply the view volume's rotation matrix */
- multmatrix(rotate_matrix);
-
- if (hardware != ECLIPSE8)
- /* depth cue markers and curve in white */
- lRGBrange(50, 50, 50, 255, 255, 255,
- getgdesc(GD_ZMIN), getgdesc(GD_ZMAX));
- }
- else
- {
- if (hardware != ECLIPSE8)
- cpack(0xffffff);
-
- set_two_d_view();
- }
-
- if (hardware == ECLIPSE8)
- color(WHITE);
-
- /* display the control point marker */
- if (markers)
- draw_markers();
-
- /* 3 control points doth not a curve make */
- if (current_markers > 3)
- {
- setlinestyle(line_style);
-
- /* Draw the curve with multiple control points */
- crvn(current_markers, geometry);
-
- if(motion)
- update_positions();
- }
-
- /* display the convex hulls */
- if (hulls)
- {
- setlinestyle(SOLID);
-
- if (display_mode == THREE_D)
- {
- if(hardware != ECLIPSE8)
- lRGBrange(0, 50, 0, 0, 255, 0,
- getgdesc(GD_ZMIN), getgdesc(GD_ZMAX));
- }
- else if (hardware != ECLIPSE8)
- cpack(0xff00);
-
- if (hardware == ECLIPSE8) color(GREEN);
-
- draw_hulls();
- }
-
-
-
- if (display_mode == THREE_D)
- {
- /* depth cue the cube in red */
- setlinestyle(SOLID);
-
- if (hardware != ECLIPSE8)
- lRGBrange(100, 0, 0, 255, 0, 0,
- getgdesc(GD_ZMIN), getgdesc(GD_ZMAX));
- else
- color(RED);
-
- draw_cube();
-
- if (moving)
- {
- if (hardware != ECLIPSE8)
- lRGBrange(0,50,50,0,255,255,
- getgdesc(GD_ZMIN), getgdesc(GD_ZMAX));
- else
- color(CYAN);
-
- draw_drop_lines(geometry[nailed_marker]);
- }
- }
-
- /* if smearing, we are already drawing in front buffer */
- if (! smear)
- swapbuffers();
- }
-
-
- /*
- * Clears the window and reinitialized the control point markers to
- * none.
- */
- void clear_window(void)
- {
- current_markers = 0;
-
- czclear(0,getgdesc(GD_ZMAX));
-
- draw_display();
- }
-
-
- /*
- * Draws the digits representing the control point markers on the
- * screen. The actual control point is the character's lower-left
- * origin.
- */
- void draw_markers(void)
- {
- int i;
- char marker_string[3];
-
- for (i=0; i<current_markers; i++)
- {
- sprintf(marker_string, "%d", i);
- cmov(geometry[i][0], geometry[i][1], geometry[i][2]);
- charstr(marker_string);
- }
- }
-
-
-
- void draw_drop_lines(Coord c[3])
- {
- Coord a[3],b[3];
-
- a[0] = c[0];
- a[1] = c[1];
- a[2] = -1.0;
- b[0] = c[0];
- b[1] = c[1];
- b[2] = 1.0;
- bgnline();
- v3f(a);
- v3f(b);
- endline();
-
- a[0] = c[0];
- a[1] = -1.0;
- a[2] = c[2];
- b[0] = c[0];
- b[1] = 1.0;
- b[2] = c[2];
- bgnline();
- v3f(a);
- v3f(b);
- endline();
-
- a[0] = -1.0;
- a[1] = c[1];
- a[2] = c[2];
- b[0] = 1.0;
- b[1] = c[1];
- b[2] = c[2];
- bgnline();
- v3f(a);
- v3f(b);
- endline();
- }
-
-
- /* Draw the convex hulls by connecting the series of control points
- * with lines.
- */
- void draw_hulls(void)
- {
- int i;
-
- bgnline();
- for (i=0; i<current_markers; i++)
- v3f(geometry[i]);
- endline();
- }
-
-
- /*
- * Updates the positions of the control points by adding the offset
- * for each dimension to the markers position. Checks for collisions
- * with the walls of the view volume, which is defined between -1 and
- * 1 along each axis. Note that even though the z component is ignored
- * in 2D mode, it is updated anyway.
- */
- void update_positions(void)
- {
- int i, j;
- float new_position, overshoot;
-
- /* for each control point marker */
- for(i=0; i<current_markers; i++)
-
- if (!moving || (i != nailed_marker))
-
- /* for each dimension x,y,z */
- for(j=0; j<3; j++)
- {
- new_position = geometry[i][j] + (float)speed*offset[i][j];
-
- if (new_position < -1.0)
- {
- offset[i][j] = -offset[i][j];
- overshoot = -1.0 - new_position;
- geometry[i][j] = -1.0 + overshoot;
- }
- else if (new_position > 1.0)
- {
- offset[i][j] = -offset[i][j];
- overshoot = new_position - 1.0;
- geometry[i][j] = 1.0 - overshoot;
- }
- else
- geometry[i][j] = new_position;
- }
- }
-
-
-
- static float last_x, last_y;
-
-
- /*
- * Called by the event manager whenever the left mouse button is pressed.
- * Used to add a control point. In 2D mode, the control point is added
- * at the exact location of the mouse click. In 3D mode, the point
- * will be projected onto the z=0 plane, then is given a random z
- * value. In both modes, points are given random offsets used to
- * create motion. This offset is added to the control point's location
- * whenever motion is active.
- */
- void add_control_point(void)
- {
- Coord x, y;
- long mx, my;
-
- if (current_markers < MAX_MARKERS)
- {
- /* scale the offsets so they are not outrageous for the size
- of the window (although the window may change) */
- offset[current_markers][0] = (generate_random_float(2.0) -
- 1.0)/(float)size_x;
- offset[current_markers][1] = (generate_random_float(2.0) -
- 1.0)/(float)size_y;
- offset[current_markers][2] = (generate_random_float(2.0) -
- 1.0)/(float)size_x;
-
- if (display_mode == TWO_D)
- {
- /* Scale mouse values to square around -1.0 to 1.0 */
- x = 2.0*((Coord)(getvaluator(MOUSEX) - origin_x)/size_x - 0.5);
- y = 2.0*((Coord)(getvaluator(MOUSEY) - origin_y)/size_y - 0.5);
-
- geometry[current_markers][0] = x;
- geometry[current_markers][1] = y;
- geometry[current_markers][2] = generate_random_float(2.0) - 1.0;
-
- /* scale the offsets so they are not outrageous for the size
- of the window (although the window may change) */
- offset[current_markers][0] = (generate_random_float(2.0) -
- 1.0)/(float)size_x;
- offset[current_markers][1] = (generate_random_float(2.0) -
- 1.0)/(float)size_y;
- offset[current_markers][2] = (generate_random_float(2.0) -
- 1.0)/(float)size_x;
-
- nailed_marker = current_markers;
- current_markers++;
-
- moving = TRUE;
-
- mx = getvaluator(MOUSEX);
- my = getvaluator(MOUSEY);
-
- /* Scale mouse values to square around -1.0 to 1.0 */
- last_x = 2.0*((Coord)(mx - origin_x)/size_x - 0.5);
- last_y = 2.0*((Coord)(my - origin_y)/size_y - 0.5);
-
- }
- else /* display_mode == THREE_D, use spaced */
- {
- if (within_cube)
- {
- extern Coord box_limit[3][2];
-
- start_spaced();
-
- geometry[current_markers][0] = 0.0;
- geometry[current_markers][1] = 0.0;
- geometry[current_markers][2] = 0.0;
-
- set_three_d_view();
- multmatrix(rotate_matrix);
- getmatrix(everything_matrix);
-
- nailed_marker = current_markers;
- current_markers++;
- moving = TRUE;
-
- spaced(everything_matrix, geometry[nailed_marker], box_limit);
-
- /* next three lines compensate for a bug in spaced,
- they make the added point fall under the cursor */
- setvaluator(MOUSEX,getvaluator(MOUSEX)+1,0,XMAXSCREEN);
- setvaluator(MOUSEY,getvaluator(MOUSEY)+1,0,YMAXSCREEN);
- spaced(everything_matrix, geometry[nailed_marker], box_limit);
- }
- }
-
- qdevice(MOUSEX);
- qdevice(MOUSEY);
- draw_display();
- }
- }
-
-
- /*
- * Called by the event manager whenever the backspace key is pressed.
- * Deletes the control points closest to the cursor, renumbers the
- * remaining control points, and redraws the curve.
- */
- void delete_control_point(void)
- {
- int i, j, close_marker;
- float x, y;
-
- if (current_markers)
- {
- /* Scale mouse values to square around -1.0 to 1.0 */
- x = 2.0*((Coord)(getvaluator(MOUSEX) - origin_x)/size_x - 0.5);
- y = 2.0*((Coord)(getvaluator(MOUSEY) - origin_y)/size_y - 0.5);
-
- close_marker = get_close_marker(x, y);
-
- current_markers--;
- for (i=close_marker; i<current_markers; i++)
- for (j=0; j<3; j++)
- geometry[i][j] = geometry[i+1][j];
-
- draw_display();
- }
- }
-
-
- /*
- * Called by decode_middle_mouse whenever the middle mouse button is
- * pressed and in 2D mode. Chooses the control point closest to the
- * cursor and 'nails' the control point to the motion of the cursor.
- * Tons of fun when motion is turned on.
- */
- void move_control_point(int marker)
- {
- Coord x, y;
- long mx, my;
-
- if (display_mode == TWO_D)
- {
- nailed_marker = marker;
-
- moving = TRUE;
-
- mx = getvaluator(MOUSEX);
- my = getvaluator(MOUSEY);
-
- /* Scale mouse values to square around -1.0 to 1.0 */
- last_x = 2.0*((Coord)(mx - origin_x)/size_x - 0.5);
- last_y = 2.0*((Coord)(my - origin_y)/size_y - 0.5);
-
- }
- else /* display_mode == THREE_D, use spaced */
- {
- extern Coord box_limit[3][2];
-
- start_spaced();
-
- set_three_d_view();
- multmatrix(rotate_matrix);
- getmatrix(everything_matrix);
-
- nailed_marker = marker;
-
- moving = TRUE;
- spaced(everything_matrix, geometry[nailed_marker], box_limit);
- }
- qdevice(MOUSEX);
- qdevice(MOUSEY);
- draw_display();
- }
-
-
- void track_motion()
- {
- long mx, my;
-
- /* Scaled mouse values */
- float new_x, new_y, dx, dy;
-
- mx = getvaluator(MOUSEX);
- my = getvaluator(MOUSEY);
-
- new_x = 2.0*((Coord)(mx - origin_x)/size_x - 0.5);
- dx = new_x-last_x;
- geometry[nailed_marker][0] += dx;
-
- /* stay bewteen the lines... */
- if (geometry[nailed_marker][0] < -1.0)
- geometry[nailed_marker][0] = -1.0;
- else if (geometry[nailed_marker][0] > 1.0)
- geometry[nailed_marker][0] = 1.0;
-
- last_x = new_x;
-
- new_y = 2.0*((Coord)(my - origin_y)/size_y - 0.5);
- dy = new_y-last_y;
- geometry[nailed_marker][1] += dy;
-
- if (geometry[nailed_marker][1] < -1.0)
- geometry[nailed_marker][1] = -1.0;
- else if (geometry[nailed_marker][1] > 1.0)
- geometry[nailed_marker][1] = 1.0;
-
- last_y = new_y;
- }
-
-
- /*
- * Returns the index of the closest control point marker to x,y where
- * x and y are in scaled screen coordinates between -1.0 and 1.0.
- */
- int get_close_marker(float x, float y)
- {
- float max_dist, current_dist, dx, dy;
- int close_marker, i;
-
- /* furthest point can be in -1 to 1 square */
- max_dist = 2.0*fsqrt(2.0);
-
- for(i=0; i<current_markers; i++)
- {
- dx = geometry[i][0] - x;
- dy = geometry[i][1] - y;
- current_dist = fsqrt(dx*dx + dy*dy);
-
- if (current_dist <= max_dist)
- {
- max_dist = current_dist;
- close_marker = i;
- }
- }
- return(close_marker);
- }
-
-
- /*
- * Returns a pseudo-random float between 0 and n.
- */
- float generate_random_float(float n)
- {
- static seeded = FALSE;
- float result, r;
-
- if (! seeded)
- {
- srand48((long) getvaluator(MOUSEX));
- seeded = TRUE;
- }
-
- r = (float) drand48();
- result = n * r;
-
- return(result);
- }
-
-
- /* The vertices of a cube centered about the origin with width 2 */
- Coord cube_vertex[8][3] =
- {
- {-1.0, -1.0, -1.0},
- {-1.0, -1.0, 1.0},
- {-1.0, 1.0, 1.0},
- {-1.0, 1.0, -1.0},
- { 1.0, -1.0, -1.0},
- { 1.0, -1.0, 1.0},
- { 1.0, 1.0, 1.0},
- { 1.0, 1.0, -1.0}
- };
-
-
- /*
- * Draws the cube with vertices defined above.
- */
- void draw_cube(void)
- {
- bgnclosedline();
- v3f(cube_vertex[0]);
- v3f(cube_vertex[1]);
- v3f(cube_vertex[2]);
- v3f(cube_vertex[3]);
- endclosedline();
-
- bgnclosedline();
- v3f(cube_vertex[4]);
- v3f(cube_vertex[5]);
- v3f(cube_vertex[6]);
- v3f(cube_vertex[7]);
- endclosedline();
-
- bgnline();
- v3f(cube_vertex[0]);
- v3f(cube_vertex[4]);
- endline();
-
- bgnline();
- v3f(cube_vertex[1]);
- v3f(cube_vertex[5]);
- endline();
-
- bgnline();
- v3f(cube_vertex[2]);
- v3f(cube_vertex[6]);
- endline();
-
- bgnline();
- v3f(cube_vertex[3]);
- v3f(cube_vertex[7]);
- endline();
- }
-
-
- void fake_view_volume(void)
- {
- loadname(1);
- draw_volume();
- }
-
- void draw_volume(void)
- {
- /* x = 1.0 */
- bgnpolygon();
- v3f(cube_vertex[4]);
- v3f(cube_vertex[5]);
- v3f(cube_vertex[6]);
- v3f(cube_vertex[7]);
- endpolygon();
-
- /* x = -1.0 */
- bgnpolygon();
- v3f(cube_vertex[0]);
- v3f(cube_vertex[1]);
- v3f(cube_vertex[2]);
- v3f(cube_vertex[3]);
- endpolygon();
-
- /* y = 1.0 */
- bgnpolygon();
- v3f(cube_vertex[3]);
- v3f(cube_vertex[2]);
- v3f(cube_vertex[6]);
- v3f(cube_vertex[7]);
- endpolygon();
-
- /* y = -1.0 */
- bgnpolygon();
- v3f(cube_vertex[0]);
- v3f(cube_vertex[1]);
- v3f(cube_vertex[5]);
- v3f(cube_vertex[4]);
- endpolygon();
-
- /* z = 1.0 */
- bgnpolygon();
- v3f(cube_vertex[1]);
- v3f(cube_vertex[2]);
- v3f(cube_vertex[6]);
- v3f(cube_vertex[5]);
- endpolygon();
-
- /* z = -1.0 */
- bgnpolygon();
- v3f(cube_vertex[0]);
- v3f(cube_vertex[3]);
- v3f(cube_vertex[7]);
- v3f(cube_vertex[4]);
- endpolygon();
- }
-
- void fake_control_volumes(void)
- {
- int i;
-
- for(i=0; i<current_markers; i++)
- {
- pushmatrix();
- translate(geometry[i][0], geometry[i][1], geometry[i][2]);
- scale(.02, .02, .02);
- pushname(i);
- draw_volume();
- popname();
- popmatrix();
- }
- }
-
-
- Boolean hit_control_point(int *marker)
- {
- long hit;
- short buffer[2];
-
- picksize(10, 10);
-
-
- initnames();
- pick(buffer, 2);
-
- if (display_mode == TWO_D)
- set_two_d_view();
- else
- {
- set_three_d_view();
- multmatrix(rotate_matrix);
- }
-
- fake_control_volumes();
- hit = endpick(buffer);
-
- *marker = buffer[1];
-
- return(hit != 0);
- }
-
-